'''
@Description: In User Settings Edit
@Author: your name
@Date: 2019-07-09 09:20:38
@LastEditTime : 2020-02-01 11:57:18
@LastEditors  : Please set LastEditors
'''

from ...pao_python.pao.data import process_db, dataframe_to_list, DataProcess, data_to_string_date
from ...pao_python.pao.service.security.security_utility import get_current_account_id
from ...service.common import insert_data, find_data, update_data, delete_data, get_condition, get_info, get_cur_time, get_code, get_current_user_id
import pandas as pd
import uuid
import datetime
import re
import hashlib
import copy
import uuid
from enum import Enum
from ...pao_python.pao.service.data.mongo_db import MongoService, MongoFilter, C, N, F, as_date


class Status(Enum):
    bill_add = 'new'
    bill_valid = 'valid'
    bill_invalid = 'invalid'


class OperationType(Enum):
    add = 'add'
    update = 'update'
    delete = 'del'

# 人员审核状态


class PersonalState(Enum):
    # 通过
    adopt = 'adopt'
    # 不通过
    noPassage = 'noPassage'
    # 审核中
    inReview = 'inReview'


class TypeId(Enum):
    '''审批类型Id'''
    user = 'user'
    organization = 'organization'
    serviceItem = 'serviceItem'
    transaction = 'transaction'
    serviceProvider = 'serviceProvider'
    serviceType = 'serviceType'
    serviceItemEvaluate = 'serviceItemEvaluate'
    businessArea = 'businessArea'
    # 床位类别
    bedPositionType = 'bedPositionType'
    # 服务项目
    servicesProject = 'servicesProject'
    # 服务项目类别
    servicesItemCategory = 'servicesItemCategory'
    # 服务适用范围
    serviceScope = 'serviceScope'
    # 服务选项
    serviceOption = 'serviceOption'
    # 服务包
    serviceItemPackage = 'serviceItemPackage'
    # 服务产品
    serviceProduct = 'serviceProduct'
    nursing = 'nursing'
    bed = 'bed'
    # 住宿记录
    accommodationRecord = 'accommodationRecord'
    # 财务管理
    financial = 'financial'
    # 服务记录
    serviceRecord = 'serviceRecord'
    # 台账
    serviceLedger = 'serviceLedger'
    # 预约登记
    reservationRegistration = 'reservationRegistration'
    # 服务订单
    serviceOrder = 'serviceOrder'
    # 需求模板
    requirementTemplate = 'requirementTemplate'
    # 首页
    homePage = 'homePage'
    # 评估项目
    assessmentProject = 'assessmentProject'
    # 评估模板
    assessmentTemplate = 'assessmentTemplate'
    # 行为能力评估
    behavioralCompetenceAssessment = 'behavioralCompetenceAssessment'
    # 能力评估
    competenceAssessment = 'competenceAssessment'
    # 入住登记
    checkIn = 'checkIn'
    # 服务人员登记
    servicePerson = 'servicePerson'
    # 住宿区域类型
    hotelZoneType = 'hotelZoneType'
    # 住宿区域
    hotelZone = 'hotelZone'
    # 需求项目
    requirementItem = 'requirementItem'
    # 需求类型
    requirementType = 'requirementType'
    # 需求类别
    requirementProject = 'requirementProject'
    # 公告
    announcement = 'announcement'
    # 文章类型
    articleType = 'articleType'
    # 评论类型
    commentType = 'commentType'
    # 新闻
    news = 'news'
    # 服务人员
    servicePersonal = 'servicePersonal'
    # 服务结算
    serviceSettlement = 'serviceSettlement'
    # 医疗欠费
    medicalArrears = 'medicalArrears'
    # 水电抄表
    hydropower = 'hydropower'
    # 评论管理
    comment = 'comment'
    # 任务管理
    task = 'task'
    # 任务类型管理
    taskType = 'taskType'
    # 信息管理
    message = 'message'
    # 退住
    retreat = 'retreat'
    # 补贴管理
    allowance = 'allowance'
    # 补贴审批
    allowanceSubsidy = 'allowanceSubsidy'
    # 高龄津贴名单
    oldAgeList = 'oldAgeList'
    # 请假销假
    LeaveRecord = 'LeaveRecord'
    # 文章
    article = 'article'
    # 文章
    device = 'device'
    # 社会群体类型
    socialGroupType = 'socialGroupType'
    # 监控信息
    monitor = 'monitor'
    # 按钮一键生成与请假/销假相关的服务记录
    btnCreateRecord = 'btnCreateRecord'
    # 服务订单分派
    serviceTask = 'serviceTask'
    # PT_Role
    ptRole = 'ptRole'
    # PT_Permission
    ptPermission = 'ptPermission'
    # PT_Set_Role
    ptSetRole = 'ptSetRole'
    # 杂费
    incidental = 'incidental'
    # 餐费
    footCost = 'foodCost'
    # 医疗费用
    medicalCost = 'medicalCost'
    # 尿片费用
    diaperCost = 'diaperCost'
    # 角色关联
    setRole = 'setRole'
    # 角色设置
    role = 'role'
    # 护理项目
    nursingProject = 'nursingProject'
    # 护理模板
    nursingTemplate = 'nursingTemplate'
    # 护理记录
    nursingRecode = 'nursingRecode'
    # 慈善管理
    charitableDonate = 'charitableDonate'
    # 慈善记录表
    charitableRecord = 'charitableRecord'
    # 慈善项目
    charitableProject = 'charitableProject'
    # 个人募捐
    charitableRecipient = 'charitableRecipient'
    # 慈善会资料
    charitableSociety = 'charitableSociety'
    # 捐款审批
    charitableAppropriation = 'charitableAppropriation'
    # 冠名基金
    charitableTitleFund = 'charitableTitleFund'
    # 志愿者服务类别
    volunteerServiceCategory = 'volunteerServiceCategory'
    # 收付款过程记录
    financialReceivableProcess = 'financialReceivableProcess'
    # 账户
    account = 'account'
    # 账户出入记录
    accountRecord = 'accountRecord'
    # 账户充值
    accountRecharge = 'accountRecharge'
    # 需求定义
    approvalDefine = 'approvalDefine'
    approvalProcess = 'approvalProcess'
    # 第三方支付
    thirdPartPay = 'thirdPartPay'
    # 活动
    activity = 'activity'
    # 活动报名
    activityParticipate = 'activityParticipate'
    # 活动签到
    activitySignin = 'activitySignin'
    # 活动室
    activityRoom = 'activityRoom'
    # 活动类型
    activityType = 'activityType'
    # 活动室预约
    activityRoomReservation = 'activityRoomReservation'
    # 人员类别
    personnelClassification = 'personnelClassification'
    # 预约服务
    reserveService = 'reserveService'
    # 呼叫中心
    emiCallCenter = 'emiCallCenter'
    # 知识库
    knowledgeBase = 'knowledgeBase'
    # 行政区域
    administrationDivision = 'administrationDivision'
    # 人员关系
    userRelationShip = 'userRelationShip'
    # 老友圈
    friendsCircle = 'friendsCircle'
    # 收藏/关注
    followCollection = 'followCollection'
    # 意见反馈
    opinionFeedback = 'opinionFeedback'
    # 订单评论
    orderComment = 'orderComment'
    # 需求
    demand = 'demand'
    # 短信
    sms = 'sms'
    # 竞单
    bidding = 'bidding'


class BillData():
    '''单据对象'''

    def __init__(self, bill_type, type_id, initiator, related_parties, body_mes, table_name):
        '''构造函数'''
        self.bill_type = bill_type
        self.type_id = type_id
        self.initiator = initiator
        self.related_parties = related_parties
        self.body_mes = body_mes
        self.bill_code = get_code()
        self.bill_status = Status.bill_add.value
        self.version = 1
        self.table_name = table_name

    def to_dict(self):
        return self.__dict__


class BillManageService(MongoService):
    def __init__(self, db_addr, db_port, db_name, db_user, db_pwd, inital_password, session):
        DataProcess.__init__(self, db_addr, db_port, db_name, db_user, db_pwd)
        # self.db_name = db_name
        self.inital_password = inital_password
        self.session = session

    def add_bill(self, bill_type, type_id, datas, table_names):
        '''# 新增单据信息'''
        res = False

        def process_func(db):
            nonlocal res
            if isinstance(table_names, list):
                if isinstance(datas, list):
                    res = False
                else:
                    '''非法的传入参数，table_names为集合的时候，datas也必须为集合'''
                    return res
            bill_data = BillData(bill_type, type_id, '发起人',
                                 '关联方', datas, table_names)
            data_info = get_info(bill_data.to_dict(), self.session)
            # 查询当前登录账号的用户Id
            person_id = get_current_user_id(self.session)
            data_info['initiator_id'] = person_id
            # 根据单据类型查找单据签核清单
            bill_type_mes = find_data(
                db, 'PT_Bill_Type', {'id': type_id})
            if len(bill_type_mes) > 0:
                data_info['signature_list'] = bill_type_mes[0]['signature_list']
                insert_data(db, 'PT_Bill', data_info)
            else:
                insert_data(db, 'PT_Bill', data_info)
                bill_id = self.sign_bill(data_info['id'])
                # 直接审核新增数据
                self.common_add(data_info['id'], data_info['body_mes'],
                                data_info['table_name'], bill_type)
            res = 'Success'
        process_db(self.db_addr, self.db_port, self.db_name,
                   process_func, self.db_user, self.db_pwd)
        return res

    def sign_bill(self, bill_id):
        '''# 直接签核单据'''
        res = False

        def process_func(db):
            nonlocal res
            mes = find_data(db, 'PT_Bill', {'id': bill_id})
            if len(mes) > 0:
                bill_mes = get_info(mes[0], self.session)
                # 已签核
                # bill_mes['signature_status'] = 'Y'
                # 生效
                bill_mes['bill_status'] = Status.bill_valid.value
                sign_result = update_data(
                    db, 'PT_Bill', bill_mes, {'id': bill_id})
                if sign_result:
                    res = bill_id
        process_db(self.db_addr, self.db_port, self.db_name,
                   process_func, self.db_user, self.db_pwd)
        return res

    def common_add(self, bill_id, datas, table_names, option_type):
        res = False

        def process_func(db):
            nonlocal res
            table_name_list = []
            data_l = []
            if isinstance(table_names, list):
                if isinstance(datas, list):
                    table_name_list = table_names
                    if len(table_name_list) == 1 and len(datas) > 1:
                        data_l.append(datas)
                    else:
                        data_l = datas
                else:
                    '''非法的传入参数，table_names为集合的时候，datas也必须为集合'''
                    return res
            else:
                if isinstance(datas, list):
                    table_name_list.append(table_names)
                    if len(datas) > 1:
                        data_l.append(datas)
                    else:
                        data_l = datas
                else:
                    table_name_list.append(table_names)
                    data_l.append(datas)
            for i, table_name in enumerate(table_name_list):
                table_data = data_l[i]

                data_list = []
                if isinstance(table_data, list):
                    data_list = table_data
                else:
                    data_list.append(table_data)

                if option_type == OperationType.add.value:
                    self.add_data_many(bill_id, data_list, table_name)
                elif option_type == OperationType.update.value:
                    self.update_data_many(bill_id, data_list, table_name)
                elif option_type == OperationType.delete.value:
                    for version_data in data_list:
                        self.del_data(bill_id, version_data, table_name)
                # for version_data in data_list:
                #     if option_type == OperationType.add.value:
                #         self.add_data(bill_id, version_data, table_name)
                #     if option_type == OperationType.update.value:
                #         self.update_data(
                #             bill_id, version_data, table_name)
                #     if option_type == OperationType.delete.value:
                #         self.del_data(bill_id, version_data, table_name)
            res = 'Success'
        process_db(self.db_addr, self.db_port, self.db_name,
                   process_func, self.db_user, self.db_pwd)
        return res

    def add_data_many(self,  bill_id, version_data, table_name):
        '''
        1，为version_data增加相关的版本管理的数据
        2，插入处理过的数据到数据库
        '''
        operator_id = get_current_user_id(self.session)
        tep_data = [get_info(i, self.session) for i in version_data]
        insert_data = []
        for i in tep_data:
            i.update({'GUID': str(uuid.uuid1()), 'version': 1, 'bill_status': Status.bill_valid.value,
                      'valid_bill_id': bill_id, 'bill_operator': operator_id})
            insert_data.append(i)
        try:
            self.insert_many(insert_data, table_name)
        except:
            res = False
            print(str(table_name)+' 表插入失败')
        else:
            res = True
            print(str(table_name)+' 表插入成功')
        return res

    def add_data(self,  bill_id, version_data, table_name):
        '''# 新增数据'''
        res = False

        def process_func(db):
            nonlocal res
            if 'id' in version_data.keys():
                data_mes = find_data(
                    db, table_name, {'id': version_data['id'], 'invalid_bill_id': bill_id})
                if len(data_mes) > 0:
                    data_info = data_mes[0].copy()
                    data_info.update(version_data)
                    data_info.pop("_id")
                    data_info.pop("invalid_bill_id")
                else:
                    data_info = get_info(version_data, self.session)
            else:
                data_info = get_info(version_data, self.session)
            data_info['GUID'] = str(uuid.uuid1())
            if 'version' in data_info.keys():
                data_info['version'] = data_info['version'] + 1
            else:
                data_info['version'] = 1
            data_info['bill_status'] = Status.bill_valid.value
            data_info['valid_bill_id'] = bill_id
            # 记录操作人
            data_info['bill_operator'] = get_current_user_id(self.session)

            insert_data(db, table_name, data_info)
            # if result:
            res = 'Success'
        process_db(self.db_addr, self.db_port, self.db_name,
                   process_func, self.db_user, self.db_pwd)
        return res

    def update_data_many(self, bill_id, version_data, table_name):
        '''
        1,查询待更新数据的上一条数据，并修改
        2，根据查询结果更新待插入数据
        '''
        operator_id = get_current_user_id(self.session)
        update_insert_data = []
        new_insert_data = []
        old_GUID = []

        ids = [i['id'] for i in version_data]
        _filter = MongoFilter()
        _filter.match((C('id').inner(ids)) & (C('bill_status') == Status.bill_valid.value))\
               .project({'_id': 0, 'invalid_bill_id': 0})
        old_datas = self.query(_filter, table_name)
        old_ids = [i['id'] for i in old_datas]
        for i in version_data:
            if i['id'] in old_ids:
                tep = [t for t in old_datas if t['id'] == i['id']]
                old_data = copy.deepcopy(tep[0])
                old_data['invalid_bill_id'] = bill_id
                old_data['bill_status'] = Status.bill_invalid.value
                #self.update({'GUID': old_data['GUID']},old_data,table_name)
                old_GUID.append(old_data['GUID'])
                old_data.update(i)
                old_data.pop("invalid_bill_id")
                old_data['version'] = old_data['version'] + 1
                old_data.update({'GUID': str(uuid.uuid1()), 'bill_status': Status.bill_valid.value,
                                 'valid_bill_id': bill_id, 'bill_operator': operator_id, 'modify_date': datetime.datetime.now()})
                update_insert_data.append(old_data)
            else:
                new_insert_data.append(i)
        if len(new_insert_data) > 0:
            res = self.add_data_many(bill_id, new_insert_data, table_name)
            print(str(table_name)+' 表数据插入成功')
        if len(update_insert_data) > 0:
            try:
                self.update({'GUID': {'$in': old_GUID}}, {
                            'invalid_bill_id': bill_id, 'bill_status': Status.bill_invalid.value}, table_name, True)
                self.insert_many(update_insert_data, table_name)
            except:
                res = False
                print(str(table_name)+' 表更新失败')
            else:
                res = True
                print(str(table_name)+' 表更新成功')
        return res

    def update_data(self, bill_id, version_data, table_name):
        '''# 修改数据(把状态改为失效-) version_data是新修改的信息'''
        res = False

        def process_func(db):
            nonlocal res
            # 查询原来的数据
            data_info = find_data(
                db, table_name, {'id': version_data['id'], 'bill_status': Status.bill_valid.value})
            if len(data_info) > 0:
                data_info[0]['bill_status'] = Status.bill_invalid.value
                # 把原本数据的失效单据Id改为新的单据id
                data_info[0]['invalid_bill_id'] = bill_id
                data_info[0].pop('_id')
                update_data(db, table_name, data_info[0], {
                    'GUID': data_info[0]['GUID']})
                self.add_data(bill_id, version_data, table_name)
            res = 'Success'
        process_db(self.db_addr, self.db_port, self.db_name,
                   process_func, self.db_user, self.db_pwd)
        return res

    def del_data(self, bill_id, version_data, table_name):
        '''# 删除数据(逻辑删除-状态改为失效)'''
        res = False

        def process_func(db):
            nonlocal res
            if 'id' in version_data:
                data_info = find_data(
                    db, table_name, {'id': version_data['id'], 'bill_status': Status.bill_valid.value})
                if len(data_info) > 0:
                    data_info[0]['bill_status'] = Status.bill_invalid.value
                    data_info[0]['invalid_bill_id'] = bill_id
                    # 记录操作人
                    data_info[0]['bill_operator'] = get_current_user_id(
                        self.session)
                    data_info[0].pop('_id')
                    update_data(db, table_name, data_info[0], {
                        'GUID': data_info[0]['GUID']})
            res = True
        process_db(self.db_addr, self.db_port, self.db_name,
                   process_func, self.db_user, self.db_pwd)
        return res

    def get_signatureBill_by_personId(self, org_list, condition, page, count):
        '''# 查询需要签核的单据'''
        _filter = MongoFilter()
        # persion_id = "a901a51e-a21f-11e9-b37a-144f8a6221df"
        persion_id = ''

        def process_func(db):
            nonlocal persion_id
            persion_id = get_current_user_id(self.session)
        process_db(self.db_addr, self.db_port, self.db_name,
                   process_func, self.db_user, self.db_pwd)

        _filter.add_fields({'new_field': self.ao.array_filter(
            "$signature_list", "aa", ((F('$aa.signature_person_id') == persion_id) & (F('$aa.status') == '')).f)}).match((C("new_field") != None) & (C("new_field") != [])).add_fields({
                'create_date': self.ao.date_to_string('$create_date'),
                'modify_date': self.ao.date_to_string('$modify_date')})\
            .match(C('organization_id').inner(org_list))\
            .project({'_id': 0, "body_mes._id": 0})
        res = self.page_query(_filter, "PT_Bill", page, count)
        # print(res, 'res')
        return res

    def get_signature_bill_by_initiatorId(self, condition, page, count):
        '''# 发起人查询已发起单据列表'''
        res = {'result': []}

        def process_func(db):
            nonlocal res
            person_id = get_current_user_id(self.session)
            cols = db['PT_Bill']
            condition['initiator_id'] = person_id
            if page and count:
                data_list = list(cols.find(condition)[
                                 (page-1)*count:(page-1)*count+count])
            else:
                data_list = list(cols.find(condition)[:])
            res['total'] = cols.find(condition).count()
            if len(data_list) > 0:
                for x in data_list:
                    otherStyleTime = data_to_string_date(x['create_date'])
                    x['create_date'] = otherStyleTime
                pd_equit = pd.DataFrame(data_list).drop(['_id'], axis=1)
                res['result'] = dataframe_to_list(pd_equit)
        process_db(self.db_addr, self.db_port, self.db_name,
                   process_func, self.db_user, self.db_pwd)
        return res

    def signature_bill_by_personId(self, signatureContent):
        '''# 单据签核 signatureContent:{id,ramark}'''
        res = 'Fail'

        def process_func(db):
            nonlocal res
            person_id = get_current_user_id(self.session)

            data_info = find_data(
                db, 'PT_Bill', {'id': signatureContent['id']})
            if len(data_info) > 0:
                data = data_info[0]
                signature_list = data['signature_list']
                flag = True
                for signature in signature_list:
                    if signature['signature_person_id'] == person_id and signature['status'] == '':
                        signature['status'] = Status.bill_valid.value
                        signature['remark'] = signatureContent['remark']
                for result in signature_list:
                    if result['status'] == '':
                        flag = False
                if flag:
                    data['bill_status'] = Status.bill_valid.value
                    self.common_add(
                        data['id'], data['body_mes'], data['table_name'], data['bill_type'])
                    # if data['bill_type'] == 'add':
                    #     # 新增版本数据
                    #     self.add_data(data['id'], data['body_mes'],
                    #                   data['table_name'])
                    # if data['bill_type'] == 'update':
                    #     # 修改版本数据
                    #     self.update_data(data['id'], data['body_mes'],
                    #                      data['table_name'])
                    # if data['bill_type'] == 'del':
                    #     # 删除版本数据 问题来了：原本数据的id只能从body_mes中取
                    #     self.del_data(
                    #         data['id'], data['body_mes'], data['table_name'])
                Sign_result = update_data(
                    db, 'PT_Bill', data, {'id': signatureContent['id']})
            if Sign_result:
                res = 'Success'
        process_db(self.db_addr, self.db_port, self.db_name,
                   process_func, self.db_user, self.db_pwd)
        return res

    def refuse_bill_by_personId(self, signatureContent):
        '''# 拒签 signatureContent:{id,ramark}'''
        res = 'Fail'
        # 从session中取出account_id
        account_id = get_current_account_id(self.session)

        def process_func(db):
            nonlocal res
            nonlocal account_id
            person_id = ''
            # 根据accountid查找userid，再用userid找人员Id
            user_mes = find_data(db, 'PT_User', {'account_id': account_id})
            if len(user_mes) > 0:
                person_mes = find_data(db, 'PT_Personnel', {
                                       'user_id': user_mes[0]['id']})
                if len(person_mes) > 0:
                    person_id = person_mes[0]['id']
            data_info = find_data(
                db, 'PT_Bill', {'id': signatureContent['id']})
            if len(data_info) > 0:
                data = data_info[0]
                signature_list = data['signature_list']

                for signature in signature_list:
                    if signature['signature_person_id'] == person_id and signature['status'] == '':
                        signature['status'] = Status.bill_invalid.value
                        signature['remark'] = signatureContent['remark']
                        data['bill_status'] = Status.bill_invalid.value
                Sign_result = update_data(
                    db, 'PT_Bill', data, {'id': signatureContent['id']})
            if Sign_result:
                res = 'Success'
        process_db(self.db_addr, self.db_port, self.db_name,
                   process_func, self.db_user, self.db_pwd)
        return res

    def recovery_previous_version(self, data_id, table_name):
        '''# 恢复上一版本单据'''
        res = 'Fail'
        # 通过数据id + version-1找到上一版本数据，没有的话，就没有恢复数据功能，有的话就用生效单据Id找到单据信息，body_mes就是需要恢复的数据内容，然后用body_mes走单据流程

        def process_func(db):
            nonlocal res
            new_data_mes = find_data(
                db, table_name, {'id': data_id, 'bill_status': Status.bill_valid.value})
            if len(new_data_mes) > 0:
                # 上一版本数据信息
                previous_data = find_data(
                    db, table_name, {'id': data_id, 'version': int(new_data_mes[0]['version']) - 1})
                if len(previous_data) > 0:
                    previous_bill_data = find_data(db, 'PT_Bill', {
                        'id': previous_data[0]['valid_bill_id']})
                    if len(previous_bill_data) > 0:
                        body_mes = previous_bill_data[0]['body_mes']
                        type_id = previous_bill_data[0]['type_id']
                        bill_id = self.add_bill(
                            OperationType.update.value, type_id, body_mes, table_name)
                        if bill_id:
                            res = 'Success'
                else:
                    res = "没有上一版本数据可恢复"
        process_db(self.db_addr, self.db_port, self.db_name,
                   process_func, self.db_user, self.db_pwd)
        return res
